﻿using System;
using System.Collections.Generic;
using nl.tno.ict.multitouch.wpfmultitouch.tuio;
using nl.tno.ict.multitouch.wpfmultitouch.gestures;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows;
using nl.tno.ict.multitouch.wpfmultitouch.events;
using nl.tno.ict.multitouch.wpfmultitouch.controls;
using TouchLibEvents;
using System.Timers;
using System.Linq;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Collections;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
using BitFactory.Logging;
using System.Configuration;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.ComponentModel;

namespace nl.tno.ict.multitouch.wpfmultitouch
{
    public class MTProcessing
    {
        #region privates

        /// <summary>
        /// Parses tuio events
        /// </summary>
        private TuioDump dump;

        /// <summary>
        /// Connects to tuio udp server
        /// </summary>
        private TuioClient client;

        
        /// <summary>
        /// Gesture recognition engine
        /// </summary>
        private Gesture gesture;

        /// <summary>
        /// Width of screen
        /// </summary>
        private double screenWidth;

        /// <summary>
        /// Height of screen
        /// </summary>
        private double screenHeight;

        private MTWindow mainWindow;

        
        /// <summary>
        /// Results of the hittest are stored in this list
        /// </summary>
        private List<DependencyObject> hitResultsList;

        /// <summary>
        /// Logging tool
        /// </summary>
        private CompositeLogger logger;

        #endregion

        #region constructors

        /// <summary>
        /// This static method is used for registering the TouchManager dependency property
        /// </summary>
        static MTProcessing()
        {
            TouchManagerProperty = DependencyProperty.RegisterAttached(
            "TouchManager",
            typeof(ITouchManager),
            typeof(MTCanvas),
            new UIPropertyMetadata());
        }

        public MTProcessing()
        {
            this.BlackSpotFilters = new List<BlackSpotFilter>();
        }

        #endregion

        #region events

        /// <summary>
        /// Triggered if a gesture has been recognised
        /// </summary>
        public event RecognisedGestureHandler GestureRecognised;

        public event LogEventHandler NewLogItem;


        #endregion

        #region properties

        private Dictionary<long, List<TuioMoveFingerEventArgs>> currentFingerList;
        /// <summary>
        /// list of fingers
        /// </summary>
        public Dictionary<long, List<TuioMoveFingerEventArgs>> CurrentFingerList { get { return currentFingerList; } set { currentFingerList = value; } }


        /// <summary>
        /// Every MT application has to have one main element associated with MTProcessing
        /// This can be set by the constructor
        /// </summary>
        public MTWindow MainWindow { get { return mainWindow; } }

        
        /// <summary>
        /// List of hotspots that should be ignored (TODO: move to tuio layer)
        /// </summary>
        public List<BlackSpotFilter> BlackSpotFilters { get; set; }


        public List<Visual> SelectedElements { get { return getSelectedElements() ;} }

        private double left;
        /// <summary>
        /// Set the left property. The left property is used to calculate if the click is inside the window
        /// </summary>
        public double Left { get { return left; } set { left = value; } }

        private double top;
        /// <summary>
        /// Set the top property. The top property is used to calculate if the click is inside the window
        /// </summary>
        public double Top { get { return top; } set { top = value; } }

        private bool _showFingerPos = false;
        /// <summary>
        /// To show the positions of the fingers on the (MT)screen, use this property. Default: false
        /// </summary>
        public bool ShowFingerPos { get {return this._showFingerPos; } set { this._showFingerPos = value; } }


        private bool gestureModuleEnabled = false;
        /// <summary>
        /// Set gesture module enabled
        /// </summary>
        public bool GestureModuleEnabled
        {
            get
            {
                return gestureModuleEnabled;
            }
            set
            {
                gestureModuleEnabled = value;
                if (gestureModuleEnabled)
                {
                    gesture = new Gesture();
                    gesture.GestureHandler += new RecognisedGestureHandler(_gesture_GestureHandler);
                    gesture.DebugHandler += new DebugInfoHandler(_gesture_DebugHandler);
                }
            }
        }
        /// <summary>
        /// set the screensize in gesture for converting points from tuio to real pixels
        /// </summary>
        public double ScreenSizeWidth
        {
            set { if (gesture != null) gesture.ScreenSizeWidth = value; }
        }

        /// <summary>
        /// Set the screensize in gesture for converting points from tuio to real pixels
        /// </summary>
        public double ScreenSizeHeight
        {
            set { if (gesture != null) gesture.ScreenSizeHeight = value; }
        }

        /// <summary>
        /// Sets the debug in MTCanvas;
        /// </summary>
        public bool DebugEnabled
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.DebugEnabled;
                }
                else return false;
            }
            set
            {
                if (MainWindow!=null) MainWindow.DebugEnabled = value;                
            }
        }

    

        public bool SimulationEnabled
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.SimulationEnabled;
                }
                else return false;
                
            }
            set
            {
                if (MainWindow!=null) MainWindow.SimulationEnabled = value;                
            }
        }


        private bool tuioEnabled = true;

        public bool TuioEnabled { get { return tuioEnabled; } set { tuioEnabled = value; } }

        public bool Win7Enabled
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.Win7Enabled;
                }
                else return false;

            }
            set
            {
                if (MainWindow != null) MainWindow.Win7Enabled= value;
            }
        }

        
        #endregion

        #region Singleton pattern

        private static MTProcessing _instance;

        /// <summary>
        /// Gets an instance of the static MTProcessing object
        /// </summary>
        /// <returns></returns>
        public static MTProcessing GetInstance()
        {
            if (_instance != null) return _instance;
            else
            {
                _instance = new MTProcessing();                
                return _instance;
            }
        }
        /// <summary>
        /// Gets an instance of the static MTProcessing object
        /// </summary>
        /// <param name="element">Reference to the main element (most often MTWindow)</param>
        /// <returns></returns>
        public static MTProcessing GetInstance(MTWindow element)
        {
            if (_instance != null) return _instance;
            else
            {
                _instance = new MTProcessing(element);
                return _instance;
            }
        }

        #endregion

        [DllImport("User32.dll", BestFitMapping = false, CharSet = CharSet.Auto)]
        private static extern bool SetProp(HandleRef hWnd, string propName, HandleRef data);

    
        /// <summary>
        /// Starts listening to multi-touch input devices
        /// </summary>
        public void Start()
        {

            //init logger
            InitLogging();


            if (!DesignerProperties.GetIsInDesignMode(this.MainWindow))
            {

                System.OperatingSystem osInfo = System.Environment.OSVersion;
                if (osInfo.Version.Major == 6 && osInfo.Version.Minor == 1)
                {
                    HwndSource hs = (HwndSource)PresentationSource.FromVisual(this.MainWindow);
                    SetProp(new HandleRef(this.MainWindow, hs.Handle), "MicrosoftTabletPenServiceProperty", new HandleRef(null, new IntPtr(0x01000000)));

                    this.MainWindow.StylusDown += new StylusDownEventHandler(MainWindow_StylusDown);
                    this.MainWindow.StylusMove += new StylusEventHandler(MainWindow_StylusMove);
                    this.MainWindow.StylusUp += new StylusEventHandler(MainWindow_StylusUp);
                }

            }
            
            

            // read basic settings from config file (tuio ip, ports, etc.)
            XMLSettingsReader.ReadXMLSettings();

            if (TuioEnabled)
            {

                // create tuio dump and listen to events
                dump = new TuioDump();
                dump.FingerPosChanged += new TuioMoveFingerHandler(dump_FingerPosChanged);
                dump.FingerRemoved += new TuioRemoveFingerHandler(dump_FingerRemoved);
                dump.NewFinger += new TuioNewFingerHandler(dump_NewFinger);


                // init client
                client = new TuioClient(XMLSettingsReader.CONNECTIONPORT);
                client.addTuioListener(dump);
                client.connect();

            }
            
            // create fingerlist
            CurrentFingerList = new Dictionary<long, List<TuioMoveFingerEventArgs>>();

            screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;
            screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
            
            
        }

        void MainWindow_StylusUp(object sender, StylusEventArgs e)
        {
            int key = e.StylusDevice.Id;
            this.Log(e.StylusDevice.Id + " - stylus down");
            Point p = e.GetPosition(this.MainWindow);
            dump_FingerRemoved(sender, new TuioRemoveFingerEventArgs(key));
            this.Log(e.StylusDevice.Id + " - stylus up");
            e.Handled = true;
        }

        void MainWindow_StylusMove(object sender, StylusEventArgs e)
        {
            int key = e.StylusDevice.Id;
            Point p = e.GetPosition(this.MainWindow);
            dump_FingerPosChanged(sender, new TuioMoveFingerEventArgs(new FingerObject()
             

            { Id = key, x = p.X, y = p.Y 
            }));
            e.Handled = true;
        }

        void MainWindow_StylusDown(object sender, StylusDownEventArgs e)
        {
            
            e.Handled = true;
            //this.Log(e.GetPosition(this.MainWindow).ToString());
        }

        private void InitLogging()
        {
            logger = new CompositeLogger();
            Logger consoleLogger = TextWriterLogger.NewConsoleLogger();
            logger.AddLogger("console", consoleLogger);
            
        }

        /// <summary>
        /// Creates a instance of MTProcessing
        /// MTProcessing handles the nl.tno.ict.multitouch.framework.tuio events from Touchlib and reads the XML configuration file
        /// </summary>
        /// <param name="parent">A MTCanvas or a MTGrid is a valid parent</param>
        public MTProcessing(MTWindow mainElement)
        {
            SetMainWindow(mainElement);
         
        }

        /// <summary>
        /// Sets the MainElement of the application
        /// </summary>
        /// <param name="element"></param>
        private void SetMainWindow(MTWindow element)
        {
            mainWindow = element;

            MainWindow.SizeChanged += new SizeChangedEventHandler(MTCanvas_SizeChanged);
            
            MainWindow.SimulatedFingerMoved += new TuioMoveFingerHandler(MTCanvas_SimulatedFingerMoved);
            MainWindow.SimulatedFingerRemoved += new TuioRemoveFingerHandler(MTCanvas_SimulatedFingerRemoved);
            MainWindow.SimulatedFingerNew += new TuioNewFingerHandler(MTProcessing_SimulatedFingerNew);            
        }

        

        /// <summary>
        /// A event raised from the MTCanvas or MTGrid class. Used for simulating the points with the mouse.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void MTCanvas_SimulatedFingerRemoved(object sender, TuioRemoveFingerEventArgs obj)
        {
            //Simulation finger removed
            dump_FingerRemoved(sender, obj);
        }
        /// <summary>
        /// A event raised from the MTCanvas or MTGrid class. Used for simulating the points with the mouse.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void MTCanvas_SimulatedFingerMoved(object sender, TuioMoveFingerEventArgs obj)
        {
            //Simulation finger moved
            dump_FingerPosChanged(sender, obj);
        }

        /// <summary>
        /// A event raised from the MTCanvas or MTGrid class. Used for simulating the points with the mouse.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void MTProcessing_SimulatedFingerNew(object sender, TuioNewFingerEventArgs obj)
        {
            dump_NewFinger(sender, obj);
        }

        /// <summary>
        /// Set window var positions. Used to position the debug screen (upper right corner of the canvas/grid).
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MTCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Left = MainWindow.Left();
            Top = MainWindow.Top();
            ScreenSizeHeight = MainWindow.ActualHeight;
            ScreenSizeWidth = MainWindow.ActualWidth;
            
        }

        /// <summary>
        /// Throw a new gestureRecongized event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="rg"></param>
        private void _gesture_GestureHandler(object sender, RecognisedGestureEventArgs rg)
        {
            if (GestureRecognised != null) GestureRecognised(this, new RecognisedGestureEventArgs(rg.GestureType));
        }
        /// <summary>
        /// Used when a new finger has touched the surface.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void dump_NewFinger(object sender, TuioNewFingerEventArgs obj)
        {
            
        }

        /// <summary>
        /// If a finger is removed, this event will be thrown. FingerRemoved removes the finger from the 
        /// currentfingerlist and sets the fingercount in the debug info screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void dump_FingerRemoved(object sender, TuioRemoveFingerEventArgs obj)
        {          
            MainWindow.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate()
            {
                try
                {
                    if (_showFingerPos)
                        removeFingerPos(obj);

                    if (CurrentFingerList.ContainsKey(obj.Id))
                    {
                        List<TuioMoveFingerEventArgs> templist = (List<TuioMoveFingerEventArgs>)CurrentFingerList[obj.Id];
                        //try
                        {
                            //Remove finger from the touchmanager!
                            FingerObject last = templist.Last().Finger;
                            FingerObject first = templist.First().Finger;
                            last.Element = first.Element;
                            if (first.Element != null)
                            {
                                ITouchManager tm = first.Element.GetValue(TouchManagerProperty) as ITouchManager;
                                if (tm != null)
                                {
                                    tm.FingerRaised(last);
                                }
                            }
                        }
                        //catch (Exception ex) { Console.WriteLine("FingerRemoved Error: " + ex.ToString()); }
                        //Send gestures and remove from fingerlist
                        if (gesture != null && ((templist[0].Finger.Element is MTCanvas && ((MTCanvas)templist[0].Finger.Element).GesturesEnabled) || (templist[0].Finger.Element is MTGrid && ((MTGrid)templist[0].Finger.Element).GesturesEnabled)))//Instellen of je wilt dat op een canvas of grid een gesture moet worden herkend!(Casten naar het element (Canvas of Grid) en opvragen uit dat element of er gestures herkend mogen worden!)
                            gesture.PossibleGesturePointList(templist);

                        CurrentFingerList.Remove(obj.Id);

                        this.SetFingerCount(CurrentFingerList.Count);//Write to debug!
                    }

                    return;
                }
                catch (Exception e)
                {
                    Log(LogSeverity.Error, "Finger removed: " + e.Message);
                }
                
            }
            ); //);
        }

        /// <summary>
        /// Appears when an existing fingerposition has been changed. Add's the finger ID and position to the 
        /// currentfingerlist and gets the touched element specific touchmanager
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="obj"></param>
        private void dump_FingerPosChanged(object sender, TuioMoveFingerEventArgs obj)
        {
            FingerObject workingObject = null;

            Application.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)delegate()
            {
                try
                {
                    // black spot filter check
                    if (this.BlackSpotFilters != null)
                    {
                        foreach (BlackSpotFilter bsf in this.BlackSpotFilters)
                        {
                            if (bsf.CheckFilter(obj.Finger.CurrentPosition)) return;
                        }
                    }

                    if (PointInScreen(obj.Finger.CurrentPosition, sender))
                    {
                        if (!(sender is MTWindow))//Mouse points are already relative to the window
                        {
                            calculateAbsolutePixels(obj);
                        }

                        this.SetFingerCount(this.CurrentFingerList.Count);


                        //Check of a finger already exists. True, workingobject will be set. False, workingobject is null --> go to the else
                        if (CurrentFingerList.ContainsKey(obj.Finger.Id))
                        {
                            #region existing finger
                            List<TuioMoveFingerEventArgs> fList = (List<TuioMoveFingerEventArgs>)CurrentFingerList[obj.Finger.Id];
                            obj.Finger.TickCount = Environment.TickCount;// add time for gesture recognision
                            fList.Add(obj); // add finger(position) to the current list

                            workingObject = fList[0].Finger;

                            Touch touch = new Touch(); // DoHitTest(obj.Finger);
                            //touch.Finger = fList[0].Finger;
                            touch.Finger = obj.Finger;
                            touch.Finger.Element = workingObject.Element;
                            touch.Selected = new TouchedElement(touch.Finger.Element);

                            if (touch != null && touch.Finger != null && touch.Finger.Element != null && touch.Finger.Element != workingObject.Element)
                            {
                                if ((touch.Finger.Element is MTButton) || (touch.Finger.Element is MTCheckBox) || (touch.Finger.Element is MTRadioButton))
                                {
                                    //If a touchmanager is a TouchManagerGrid don't do anything(better for the touchmanagergrid), in any other cases
                                    //remove a finger from the old object and add a new finger to the new touched object
                                    ITouchManager tm = getTouchManager(workingObject);
                                    if (tm != null)
                                    {
                                        tm.RemoveFinger(touch);//Remove finger from object (don't do mouseup events and so on)                                        
                                    }
                                    if (touch.Finger != null)
                                    {
                                        tm = getTouchManager(touch.Finger);
                                        if (tm != null)
                                        {
                                            tm.NewFinger(touch);//add new finger to new object
                                        }
                                        if (touch.Finger != null)
                                            workingObject.Element = touch.Finger.Element;//Set the new element in the list
                                        else
                                            workingObject = null;
                                    }
                                }
                                else
                                {
                                    //If the current object is the same as before, go to the update finger method
                                    ITouchManager tm = getTouchManager(workingObject);
                                    if (tm != null)
                                    {
                                        tm.UpdateFinger(touch, fList);
                                    }
                                }
                            }
                            else
                            {
                                ITouchManager tm = getTouchManager(workingObject);
                                if (tm != null)
                                {

                                    tm.UpdateFinger(touch, fList);
                                }
                            }
                            #endregion
                        }
                        else // Its a new finger
                        {
                            #region new finger
                            List<TuioMoveFingerEventArgs> t = new List<TuioMoveFingerEventArgs>();

                            obj.Finger.TickCount = Environment.TickCount;
                            t.Add(obj);
                            CurrentFingerList.Add(obj.Finger.Id, t);


                            Touch touch = DoHitTest(obj.Finger); //Do hittest
                            if (touch.Selected != null)
                            {
                                ITouchManager tm = getTouchManager(touch.Finger);
                                if (tm != null)
                                {
                                    tm.NewFinger(touch); //Add new finger to the object
                                    //tm.UpdateFinger(touch);
                                }
                            }
                            #endregion
                        }
                        if (this._showFingerPos)
                            this.showFingerPos(obj.Finger);

                        return;
                    }
                }
                catch (Exception e)
                {
                    Log(LogSeverity.Error, "Finger Pos Changed: " + e.Message);
                }
                
            }
            );
        }

        private List<Visual> getSelectedElements()
        {
            List<Visual> selected = new List<Visual>();
            foreach (List<TuioMoveFingerEventArgs> item in CurrentFingerList.Values)
            {
                selected.Add(item[0].Finger.Element);
            }
            return selected;
        }

        private void removeFingerPos(TuioRemoveFingerEventArgs fo)
        {
            try
            {
                if (MainWindow is MTWindow)
                {
                    MTWindow w = (MTWindow)MainWindow;
                    w.RemoveFinger(fo.Id);
                }                
            }
            catch(Exception ex) { Console.WriteLine("Misljerre: " + ex.ToString() ); }
        }

        /// <summary>
        /// Sets finger icon for a specific Finger ID
        /// </summary>
        /// <param name="id"></param>
        /// <param name="el"></param>
        public void SetFingerIcon(long id, FrameworkElement el)
        {
            
            FingerIcons[id] = el;     
            //if (cursors.ContainsKey(id)) { cursors[id] = el; }
        }

        public Dictionary<long, FrameworkElement> FingerIcons = new Dictionary<long, FrameworkElement>();

        

        private void showFingerPos(FingerObject fo)
        {
            if (MainWindow is MTWindow)
            {
                MTWindow w = (MTWindow)MainWindow;
                w.AddFinger(fo);
            }
            

        }

        /// <summary>
        /// Calculate absolute points of the touch. nl.tno.ict.multitouch.framework.tuio returns points from 0 to 1, in this method
        /// the points will be converted to absolute pixels. 
        /// </summary>
        /// <param name="obj"></param>
        private void calculateAbsolutePixels(TuioMoveFingerEventArgs obj)
        {
            if (MainWindow is MTWindow)
            {
                obj.Finger.x = (obj.Finger.x * SystemParameters.PrimaryScreenWidth) - ((MTWindow)MainWindow).Left();
                obj.Finger.y = (obj.Finger.y * SystemParameters.PrimaryScreenHeight) - ((MTWindow)MainWindow).Top();
            }            
        }


        /// <summary>
        /// Get the right touchmanager
        /// </summary>
        /// <param name="finger">current finger position</param>
        /// <returns>Touchmanager</returns>
        public TouchManager getTouchManager(FingerObject finger)
        {
            Visual element = finger.Element;
            return getTouchManager(element);
        }

        public void setTouchManager(Visual element, ITouchManager tm)
        {            
            element.SetValue(TouchManagerProperty, tm);
        }

        public TouchManager getTouchManager(Visual element)
        {
            TouchManager manager;
            Visual tempParent = (Visual)getParent(element);//Get the parent of the element. This is very important for right functionality



            if (tempParent is FrameworkElement)
            {
                if (tempParent is Canvas)//Normaal element...
                {
                    manager = element.GetValue(TouchManagerProperty) as TouchManager;
                    if (manager == null)
                    {
                        manager = new TouchManager((FrameworkElement)element, (FrameworkElement)tempParent, this.SimulationEnabled);
                        element.SetValue(TouchManagerProperty, manager);
                    }
                    return manager;
                }
            
                else if (tempParent is Grid)//Normaal element...
                {
                    manager = element.GetValue(TouchManagerProperty) as TouchManager;
                    if (manager == null)
                    {
                        manager = new TouchManager((FrameworkElement)element, (FrameworkElement)tempParent, this.SimulationEnabled);
                        element.SetValue(TouchManagerProperty, manager);
                    }
                    return manager;
                }
                else if (tempParent == null || tempParent == element)//Als het 'element' een repeatbutton of thumb is...(o.i.d.)
                {
                    if (tempParent is UserControl)
                    {
                        manager = element.GetValue(TouchManagerProperty) as TouchManager;
                        if (manager == null)
                        {
                            manager = new TouchManager((FrameworkElement)element, (FrameworkElement)tempParent, this.SimulationEnabled);
                            element.SetValue(TouchManagerProperty, manager);
                        }
                        return manager;
                    }
                    else
                    {
                        //manager = element.GetValue(TouchManagerProperty) as TouchManagerScroll;
                        //if (manager == null)
                        //{
                        //    manager = new TouchManagerScroll((FrameworkElement)element);
                        //    element.SetValue(TouchManagerProperty, manager);
                        //}
                        //return manager;
                    }
                }
                else // all others
                {
                  
                    manager = element.GetValue(TouchManagerProperty) as TouchManager;
                    if (manager == null)
                    {
                        manager = new TouchManager((FrameworkElement)element, (FrameworkElement)tempParent, this.SimulationEnabled);
                        element.SetValue(TouchManagerProperty, manager);
                    }
                    return manager;
                  

                }
            }
            return null;
        }

        #region hittest

        // Return the result of the hit test to the callback.
        public HitTestResultBehavior MyHitTestResult(HitTestResult result)
        {
            // Add the hit test result to the list that will be processed after the enumeration.
            if (result.VisualHit is FrameworkElement && ((FrameworkElement)result.VisualHit).Visibility == Visibility.Visible)
            {
                hitResultsList.Add(result.VisualHit);                
            }
            // Set the behavior to return visuals at all z-order levels.
            return HitTestResultBehavior.Continue;
        }
      

        #endregion

        /// <summary>
        /// Try to get the element hit
        /// </summary>
        /// <param name="obj">curren position of the finger</param>
        /// <returns>The selected element</returns>
        private Visual selectedElement(TuioMoveFingerEventArgs obj)
        {
            Touch touch = DoHitTest(obj.Finger);
            return touch.Selected.Element;
        }

        /// <summary>
        /// Get the parent. This is a canvas or a grid.
        /// </summary>
        /// <param name="element">The element</param>
        /// <returns>The parent of the element</returns>
        private DependencyObject getParent(DependencyObject element)
        {
            if (element is FrameworkElement)//Niet altijd het geval --> buttons/rectange ensfh..
            {
                if (!(((FrameworkElement)element).Parent is Window) && !(element is Thumb) && !(element is RepeatButton) && !(element is ToggleButton) && !(element is Track))
                {
                    if (((FrameworkElement)element).Parent is MTCanvas || ((FrameworkElement)element).Parent is MTGrid)
                        return ((FrameworkElement)element).Parent;
                    else
                        return getParent(((FrameworkElement)element).Parent);
                }
                else
                    return element;
            }
            else if (element is Visual)//Wel altijd het geval, drawingvisual, vectorimages.. ensfh
            {
                return element;//Nog uitbereiden.. misschien is de parent van een vectorImage wel iets bekends?
            }
            return element;
        }

        /// <summary>
        /// Checks if a object has been hit by a finger
        /// </summary>
        /// <param name="to">Position of the finger</param>
        /// <returns></returns>
        private Touch DoHitTest(FingerObject fo)
        {
            Touch t = null;

            hitResultsList = new List<DependencyObject>();            
            VisualTreeHelper.HitTest((Visual)this.MainWindow, null, new HitTestResultCallback(MyHitTestResult), new PointHitTestParameters(fo.CurrentPosition));
            

            //HitTestResult ht = VisualTreeHelper.HitTest(Parent, fo.position);
            t = new Touch(hitResultsList, fo);
            return t;
        }
        /// <summary>
        /// Checks if a click has been inside the window
        /// </summary>
        /// <param name="position"></param>
        /// <param name="sender"></param>
        /// <returns></returns>
        private bool PointInScreen(Point position, object sender)
        {
            if (sender is MTCanvas || sender is MTGrid || sender is MTWindow)
                return true;
            else
                if (position.X * screenWidth >= this.Left &&
                    position.X * screenWidth <= (this.Left + MainWindow.ActualWidth) &&
                    position.Y * screenHeight >= this.Top &&
                    position.Y * screenHeight <= (this.Top + MainWindow.ActualHeight))
                    return true;
            return false;
        }

        #region region debug
        private void _gesture_DebugHandler(object sender, DebugInfoEventArgs di)
        {
            this.Log(di.Output);
        }

        /// <summary>
        /// Can only be used when the debug is enabled, write a string to this debug screen.
        /// </summary>
        /// <param name="output"></param>
        public void Log(string output)
        {
            if (logger != null)
            {
                Log(LogSeverity.Debug, output);
                //logger.LogDebug(output);
            }
            
        }

        public void Log(LogSeverity severity, string text)
        {
            if (logger != null)
            {
                logger.Log(severity, text);                
                if (NewLogItem != null) NewLogItem(this, new LogEventArgs(text));
                
            }

        }

        /// <summary>
        /// Can only be used when the debug is enabled, write the amount of fingers to the screen.
        /// </summary>
        /// <param name="fingerCount"></param>
        public void SetFingerCount(int fingerCount)
        {
            MainWindow.SetFingerCount(fingerCount);            
        }
        #endregion

        /// <summary>
        /// Use this method to close the application properly!
        /// </summary>
        public void Stop()
        {
            if (TuioEnabled)
            {
                try
                {
                    client.disconnect();
                    
                }
                catch
                {
                    Log("Error disconnecting from TUIO server");
                }
            }
            if (gesture != null && gesture.Thread!=null && gesture.Thread.IsAlive) gesture.Thread.Abort();
        }

        #region TouchManager

        public static readonly DependencyProperty TouchManagerProperty;
        /// <summary>
        /// Set the touchmanager of the element.
        /// </summary>
        /// <param name="uiElement"></param>
        /// <param name="value"></param>
        public static void SetTouchManager(UIElement uiElement, TouchManager value)
        {
            if (uiElement != null)
                uiElement.SetValue(TouchManagerProperty, value);
        }
        #endregion
    }
}
